/*
 * @(#)Netzwerk.java	06.09.1997  Robert Denda&Didier Gutacker
 *
 */

import java.awt.*;
import java.util.Vector;
import java.net.URL;

/** 
 * Die Klasse Netzwerk stellt den Kernbereich der Simulation von Multicast 
 * Algorithmen dar.  Hier werden alle Netzwerkkomponenten verwaltet und 
 * von hieraus werden alle Ereignisse synchronisiert.  
 * Netzwerk hat einen eigenen Thread falls das Programm als Client läuft.  
 *
 * @author 	Robert Denda&Didier Gutacker
 * @version     1.1, 06.09.1997
 * @see ArchitectureComponent
 * @see Simulation
 * @see SimulationObject
 * @see SimulationFrame
 * @see Network
 * @see NetworkRIP 
 */

/**
 *
 * original author Robert Denda, changes by Didier Gutacker
 */

public abstract class Netzwerk extends SimulationObject {

  protected int numLinks = 0;
  protected int numNodes = 0;
  protected int numSenders = 0;

  // debugging
  debug DEBUG = new debug();

  protected int currentLinkNumber = 0;
  protected int currentNodeNumber = 0;
    
  protected int speed = 1;		// 0 = slow, 1 = normal, 2 = fast

  protected boolean linkAddRequest = false;
  protected boolean nodeRemoveRequest = false;
  protected boolean linkRemoveRequest = false;
  protected boolean startSendingRequest = false;
  protected boolean stopSendingRequest = false;
  protected boolean inspectRoutingTableRequest = false;

  protected SimulationFrame frame;

  protected int nodeWidth;
  protected int nodeHeight;
   
  protected NetzCanvas canvas;
  protected TextArea text;
 
  protected int infinity = 256;	// should always be greater than the sum of the weights in the net
  protected Lock infinityGuard;
  protected Lock textLock;
  protected Lock sizeChangeLock;
  protected Lock forcedPaintLock;
  protected Lock speedChangeLock;

  /**
   * Netzwerk Konstruktor bekommt Referenzen auf das Simulationsobjekt, den Frame und
   * das Zeichenbrett übergeben (zudem noch die Breite und Höhe eines Nodes in 
   * Pixeln).
   * @see Simulation
   * @see SimulationFram
   * @see NetzCanvas
   */

  public Netzwerk( Simulation simulation, SimulationFrame frame, NetzCanvas canvas, int nodeWidth, int nodeHeight ) {
    super(simulation,frame);
    this.canvas = canvas;
    this.frame = frame;
    this.nodeWidth = nodeWidth;
    this.nodeHeight = nodeHeight;
    text = frame.getTextArea();
    textLock = new Lock();
    archComponents = new Vector();
    sizeChangeLock = new Lock();
    infinityGuard = new Lock();
    forcedPaintLock = new Lock();
    speedChangeLock = new Lock();
  } // Netzwerk.Netzwerk

  /**
   * Ändert die Breite der Rechnersymbole.
   * THREADSAFE
   * @see Knoten
   * @see Netzwerk#setNodeHeight
   * @see Netzwerk#getNodeWidth
   * @see Netzwerk#getNodeHeight
   */

  public final void setNodeWidth( int w ) {
    sizeChangeLock.acquire();
    nodeWidth = w;
    sizeChangeLock.release();
  } // Netzwerk.setNodeWidth

  /**
   * Ändert die Höhe der Rechnersymbole.
   * THREADSAFE
   * @see Knoten
   * @see Netzwerk#setNodeWidth
   * @see Netzwerk#getNodeHeight
   * @see Netzwerk#getNodeWidth
   */

  public final void setNodeHeight( int h ) {
    sizeChangeLock.acquire();
    nodeHeight = h;
    sizeChangeLock.release();
  } // Netzwerk.setNodeHeight

  /**
   * Liefert die aktuelle Breite der Rechnersymbole
   * THREADSAFE
   * @see Knoten
   * @see Netzwerk#setNodeWidth
   * @see Netzwerk#getNodeHeight
   * @see Netzwerk#setNodeHeight
   */

  public final int getNodeWidth() {
    sizeChangeLock.acquire();
    int width = nodeWidth;
    sizeChangeLock.release();
    return width;
  } // Netzwerk.getNodeWidth

  /**
   * Liefert die aktuelle Höhe der Rechnersymbole
   * THREADSAFE
   * @see Knoten
   * @see Netzwerk#setNodeHeight
   * @see Netzwerk#getNodeWidth
   * @see Netzwerk#setNodeWidth
   */

  public final int getNodeHeight() {	
    sizeChangeLock.acquire();
    int height = nodeHeight;
    sizeChangeLock.release();
    return height;
  } // Netzwerk.getNodeHeight

  /**
   * Liefert den aktuellen Wert von Infinity
   * THREADSAFE
   * @see Netzwerk#setInfinity
   */

  public final int getInfinity() {
    infinityGuard.acquire();
    int returnValue = infinity;
    infinityGuard.release();
    return returnValue;
  } // Netzwerk.getInfinity

  /**
   * Setzt den aktuellen Wert von Infinity
   * THREADSAFE
   * @see Netzwerk#getInfinity
   */

  public final void setInfinity( int infinity ) {
    infinityGuard.acquire();
    this.infinity = infinity;
    infinityGuard.release();
  } // Netzwerk.setInfinity

  /**
   * Sendet an alle Netzwerkkomponenten ein "Paint Request"
   * worauf deren Threads dann asynchron das Zeichnen der 
   * jeweiligen Objekte übernehmen
   * <p>
   * THREADSAFE
   * <p>
   * @see Netzwerk#forcedPaint
   * @see ArchitectureComponent#paintRequest
   */

  public final void repaintAll() {
    for ( int i = 0; i < archComponents.size(); i += 1 ) {
      ((ArchitectureComponent)archComponents.elementAt( i )).paintRequest();
    } // for
  } // Netzwerk.repaintAll

  /**
   * Veranlaßt den aktuellen Thread alle Netzwerkkomponenten eigenständig
   * neu zu zeichnen.
   * THREADSAFE
   * @see Netzwerk#repaintAll
   * @see ArchitectureComponent#paint
   */

  public final void forcedPaint() {	
    forcedPaintLock.acquire();
    archChangeLock.acquire();
    for ( int i = 0; i < archComponents.size(); i += 1 ) {
      ((ArchitectureComponent)archComponents.elementAt( i )).paint();
    } // for
    forcedPaintLock.release();
    archChangeLock.release();
  } // Netzwerk.forcedPaint

 
  /**
   * Signalisiert, daß die "Neue Verbindung" Taste gedrückt wurde
   * @see Link
   */

  synchronized public final void addLink() {
    linkAddRequest = true;
  } // Netzwerk.addLink

  /**
   * Signalisiert, daß die "Entferne Verbindung" Taste gedrückt wurde
   * @see Link
   */

  synchronized public final void removeLink() {
    linkRemoveRequest = true;
  } // Netzwerk.removeLink

  /**
   * Signalisiert, daß die "Entferne Rechner" Taste gedrückt wurde
   * @see Node
   */

  synchronized public final void removeNode() {
    nodeRemoveRequest = true;
  } // Netzwerk.removeNode

  /**
   * Signalisiert, daß die "Starte Senden" Taste gedrückt wurde
   */

  synchronized public final void startSending() {
    startSendingRequest = true;
  } // Netzwerk.startSending

  /**
   * Signalisiert, daß die "Stopp Senden" Taste gedrückt wurde
   */

  synchronized public final void stopSending() {
    stopSendingRequest = true;
  } // Netzwerk.stopSending

  /**
   * Signalisiert, daß die "Rechner Info" Taste gedrückt wurde
   */

  synchronized public final void inspectRoutingTable() {
    inspectRoutingTableRequest = true;
  } // Netzwerk.inspectRoutingTable

  /** 
   * Liefert das Zeichenbrett auf dem das Netzwerk dargestellt wird
   */

  public final NetzCanvas getCanvas() {
    return canvas;
  } // Netzwerk.getCanvas

  /**
   * Liefert den aktuellen Frame des Netzwerks
   * @see SimulationFrame
   */

  public final SimulationFrame getFrame() {
    return frame;
  } // Netzwerk.getFrame

  /**
   * Schreibt den übergebenen Text in den Textbereich des Frames
   *
   * THREADSAFE
   *
   * @see SimulationFrame
   */

  public final void write( String s ) {
    textLock.acquire();
    text.appendText( s );
    textLock.release();
  } // Netzwerk.write

  /**
   * Schreibt den übergebenen Text mit abschließendem Zeilenvorschub
   * in den Textbereich des Frames
   *
   * THREADSAFE
   *
   * @see SimulationFrame
   */

  public final void writeln( String s ) {
    textLock.acquire();
    text.appendText( s + '\n' );
    textLock.release();
  } // Netzwerk.writeln

  /**
   * Blockt bis das Lock mit dem die Textausgabe synchronisiert wird
   * frei ist
   * @see Netzwerk#releaseTextLock
   */

  public final void acquireTextLock() {
    textLock.acquire();
  } // Netzwerk.acquireTextLock
  
  /**
   * Gibt das Lock mit dem die Textausgabe synchronisiert wird wieder
   * frei
   * @see Netzwerk#acquireTextLock
   */

  public final void releaseTextLock() {
    textLock.release();
  } // Netzwerk.releaseTextLock
   
  /**
   * Setzt die Simulationsgeschwindigkeit auf den übergebenen Wert.
   * 0 = langsam, 1 = normal, 2 = schnell
   *
   * Im Falle des Server-Betriebs wird entsprechendes Ereignis an alle
   * Clients gesendet
   *
   * THREADSAFE
   *
   * @see Netzwerk#getSpeed
   * @see SimulationServer
   */

  public final void setSpeed( int i ) {
    if ( frame.isServer() ) {
      frame.getServer().sendEvent( "setSpeed" );
      frame.getServer().sendEvent( Integer.toString( i ) );
    } // if
 
    speedChangeLock.acquire();
    speed = i;
    speedChangeLock.release();
  } // Netzwerk.setSpeed

  /**
   * Liefert die aktuelle Simulationsgeschwindigkeit
   * 0 = langsam, 1 = normal, 2 = schnell
   *
   * THREADSAFE
   *
   * @see Netzwerk#setSpeed
   */

  public final int getSpeed() {
    speedChangeLock.acquire();
    int returnValue = speed;
    speedChangeLock.release();
    return returnValue;
  } // Netzwerk.getSpeed

  /**
   * Liefert die Anzahl der sich im Netz befindenen Verbindungen 
   *
   * THREADSAFE
   *
   * @see Netzwerk#getNumNodes
   * @see Netzwerk#getNumSenders
   */

  public final int getNumLinks() {
    archChangeLock.acquire();
    int returnValue = numLinks;
    archChangeLock.release();
    return returnValue;
  } // Netzwerk.getNumLinks

  /**
   * Liefert die Anzahl der sich im Netz befindenen Rechner
   *
   * THREADSAFE
   *
   * @see Netzwerk#getNumLinks
   * @see Netzwerk#getNumSenders
   */

  public final int getNumNodes() {
    archChangeLock.acquire();
    int returnValue = numNodes;
    archChangeLock.release();
    return returnValue;
  } // Netzwerk.getNumNodes

  /**
   * Liefert die Anzahl der zur Zeit aktiven Sender
   *
   * THREADSAFE
   *
   * @see Netzwerk#getNumNodes
   * @see Netzwerk#getNumLinks
   */

  public final int getNumSenders() {
    archChangeLock.acquire();
    int returnValue = numSenders;
    archChangeLock.release();
    return returnValue;
  } // Netzwerk.getNumSenders
  
} // Netzwerk











